package com.mutual.assistance.user.api;


import com.mutual.assistance.constant.RedisConstant;
import com.mutual.assistance.exception.BizException;
import com.mutual.assistance.exception.code.ExceptionCode;
import com.mutual.assistance.response.PageParams;
import com.mutual.assistance.response.PageResult;
import com.mutual.assistance.response.R;
import com.mutual.assistance.user.model.dto.UserAndRoleDTO;
import com.mutual.assistance.user.model.dto.UserDTO;
import com.mutual.assistance.user.model.dto.UserNoticeDTO;
import com.mutual.assistance.user.model.vo.*;
import com.mutual.assistance.user.service.UserService;
import com.mutual.assistance.user.utils.SecurityUtil;
import com.mutual.assistance.utils.ThreadLocalUtils;
import com.mutual.assistance.validation.ValidationGroups;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;

import static com.mutual.assistance.exception.code.ExceptionCode.THE_USER_IS_NOT_LOGGED_IN_OR_THE_USER_DOES_NOT_EXIST;
import static com.mutual.assistance.exception.code.ExceptionCode.UNAUTHORIZED;
import static com.mutual.assistance.response.R.*;

/**
 * @author chenyuxin
 * @version 1.0
 * @description 用户相关接口
 * @date 2023/4/17 10:48
 */
@Api(value = "用户相关接口", tags = "用户相关接口")
@RestController
@Slf4j
public class UserController {

    @Resource
    private UserService userService;

    @Resource
    private TokenStore tokenStore;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public static final String AUTHORIZATION_HEADER = "Authorization";

    public static final String BLANK_SPACE = " ";

    @PostMapping("/register")
    @ApiOperation("用户注册")
    public R<String> register(
            @RequestBody @Validated(ValidationGroups.Insert.class) RegisterUserVO registerUserVO
    ) {
        userService.register(registerUserVO);
        return R.success(null, REGISTER_WAS_SUCCESSFUL);
    }

    @GetMapping("/information")
    @ApiOperation("获取用户个人信息")
    public R<UserDTO> PersonalInformation() {
        SecurityUtil.UserBO user = SecurityUtil.getUser();
        if (user == null) {
            return R.fail(UNAUTHORIZED.getCode(), UNAUTHORIZED.getMsg());
        }
        Long userId = user.getId();
        UserDTO userDTO = userService.getUserById(String.valueOf(userId));
        return R.success(userDTO, QUERY_WAS_SUCCESSFUL);
    }

    @GetMapping("/other/information/{userId}")
    @ApiOperation("获取其他用户信息")
    public R<UserDTO> otherUserInformation(@PathVariable("userId") @NotBlank(message = "其他用户主键不能为空") String userId) {
        UserDTO userDTO = userService.getUserById(userId);
        return R.success(userDTO, QUERY_WAS_SUCCESSFUL);
    }

    @GetMapping("/other/username")
    @ApiOperation("获取其他用户信息")
    public R<UserDTO> getUserByUsername(
            @RequestParam("username") @NotBlank(message = "用户id不能为空") String username
    ) {
        UserDTO userDTO = userService.getUserByUserName(username);
        return R.success(userDTO, QUERY_WAS_SUCCESSFUL);
    }

    @DeleteMapping("/list")
    @ApiOperation("删除1到多个用户")
    @PreAuthorize("hasAuthority('sysmanager_user_delete')")
    public R<String> deleteUsers(@NotNull(message = "删除的用户id不能为空") @RequestParam("userIds") List<String> userIds) {
        userService.deleteUser(userIds);
        return R.success(null, SUCCESSFULLY_DELETED);
    }

    @PostMapping("/logouts")
    @ApiOperation("用户登出")
    public R<String> logout(HttpServletRequest request) {
        String tokenStr = request.getHeader(AUTHORIZATION_HEADER);
        String token = tokenStr.split(BLANK_SPACE)[1];
        OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
        if (oAuth2AccessToken == null) {
            return R.fail(ExceptionCode.JWT_SIGNATURE.getCode(), ExceptionCode.JWT_SIGNATURE.getMsg());
        }
        OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
        tokenStore.removeAccessToken(oAuth2AccessToken);
        if (oAuth2RefreshToken != null) {
            tokenStore.removeRefreshToken(oAuth2RefreshToken);
            tokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken);
        }
        ThreadLocalUtils.removeToken();
        stringRedisTemplate.delete(RedisConstant.LOGIN_TOKEN_VALUE);
        return R.success(null, LOGIN_WAS_OUT_SUCCESSFUL);
    }

    @GetMapping("/list")
    @ApiOperation("获取所有用户信息可以通过条件过滤")
    @PreAuthorize("hasAuthority('sysmanager_user_view')")
    public R<PageResult<UserDTO>> getAllUsers(
            PageParams pageParams,
            @Validated QueryUserParamsVO queryUserParamsVO
    ) {
        PageResult<UserDTO> allUserMessage = userService.getAllUserMessage(pageParams, queryUserParamsVO);
        return R.success(allUserMessage, QUERY_WAS_SUCCESSFUL);
    }

    @PutMapping("/information")
    @ApiOperation("更新个人用户信息")
    public R<String> updateUserPersonal(
            @RequestBody @Validated UpdateUserPersonalParamsVO updateUserPersonalParamsVO
    ) {
        SecurityUtil.UserBO user = SecurityUtil.getUser();
        if (user == null) {
            return R.fail(UNAUTHORIZED.getCode(), UNAUTHORIZED.getMsg());
        }
        Long userId = user.getId();
        userService.updatePersonalMessage(updateUserPersonalParamsVO, String.valueOf(userId));
        return R.success(null, UPDATE_SUCCESS);
    }

    @PutMapping("/other/information")
    @ApiOperation("修改其他用户信息")
    @PreAuthorize("hasAuthority('sysmanager_user_edit')")
    public R<String> updateUsers(
            @RequestBody @Validated UpdateUserParamsVO updateUserParamsVO
    ) {
        userService.updateUserMessage(updateUserParamsVO);
        return R.success(null, UPDATE_SUCCESS);
    }

    @GetMapping("/user_role/{userId}")
    @ApiOperation("获取用户与角色")
    @PreAuthorize("hasAuthority('sysmanager_user_edit')")
    public R<UserAndRoleDTO> getUserAndRole(@PathVariable("userId") String userId) {
        UserAndRoleDTO userAndRole = userService.getUserAndRole(userId);
        return R.success(userAndRole, QUERY_WAS_SUCCESSFUL);
    }

    @GetMapping("/user_role/list")
    @ApiOperation("获取所有用户与角色")
    @PreAuthorize("hasAuthority('sysmanager_user_edit')")
    public R<List<UserAndRoleDTO>> getUserAndRoles() {
        List<UserAndRoleDTO> allUserAndRole = userService.getAllUserAndRole();
        return R.success(allUserAndRole, QUERY_WAS_SUCCESSFUL);
    }

    @DeleteMapping("/user_role/{userId}")
    @ApiOperation("为用户删除所有角色,如果角色id不填，默认删除该用户所有角色")
    @ApiImplicitParam(name = "roleId", value = "角色id", required = false)
    @PreAuthorize("hasAnyAuthority('sysmanager_user_delete', 'sysmanager_role_delete')")
    public R<String> removeUserRole(
            @PathVariable("userId") @NotBlank(message = "用户主键id不能为空") String userId,
            String roleId
    ) {
        userService.deleteUserRole(userId, roleId);
        return R.success(null, SUCCESSFULLY_DELETED);
    }

    @PutMapping("/user_role/{userId}/{roleId}")
    @ApiOperation("为用户添加角色")
    @PreAuthorize("hasAnyAuthority('sysmanager_user_add', 'sysmanager_role_add')")
    public R<String> addUserRole(
            @PathVariable("userId") @NotBlank(message = "用户主键不能为空") String userId,
            @PathVariable("roleId") @NotBlank(message = "角色主键不能为空") String roleId) {
        AddUserAndRoleParamsVO addUserAndRoleParamsVO = new AddUserAndRoleParamsVO();
        addUserAndRoleParamsVO.setRoleId(roleId);
        addUserAndRoleParamsVO.setUserId(userId);
        SecurityUtil.UserBO user = SecurityUtil.getUser();
        if (user == null) {
            return R.fail(UNAUTHORIZED.getCode(), UNAUTHORIZED.getMsg());
        }
        Long adminId = user.getId();
        addUserAndRoleParamsVO.setAdminId(adminId.toString());
        userService.addUserRole(addUserAndRoleParamsVO);
        return R.success(null, ADDED_SUCCESSFULLY);
    }


    @GetMapping("/email")
    @ApiOperation("发送邮件验证码")
    public R<String> sendEmailForPassword(@NotBlank(message = "用户名不能为空") String username) {
        userService.sendEmail(username);
        return R.success(null, SUCCESSFULLY_SENT);
    }

    @PutMapping("/reset")
    @ApiOperation("为用户重置密码")
    public R<String> retrievePassword(@RequestBody RetrievePasswordVO retrievePasswordVO) {
        userService.retrievePassword(retrievePasswordVO);
        return R.success(null, UPDATE_SUCCESS);
    }

    @GetMapping("/message")
    @ApiOperation("获取系统发送用户消息")
    public R<PageResult<UserNoticeDTO>> getAllMessage(PageParams pageParams) {
        SecurityUtil.UserBO userBO = checkUserIsLogin();
        PageResult<UserNoticeDTO> userAllMessage = userService.getUserAllMessage(pageParams, userBO.getUsername());
        return R.success(userAllMessage, QUERY_WAS_SUCCESSFUL);
    }

    @DeleteMapping("/message")
    @ApiOperation("删除指定用户消息")
    @ApiImplicitParam(name = "messageId", value = "用户消息主键")
    public R<String> deleteUserMessage(
            @RequestParam("messageId") @NotBlank(message = "消息主键不能为空") String messageId
    ) {
        SecurityUtil.UserBO userBO = checkUserIsLogin();
        userService.deleteUserMessage(userBO.getUsername(), messageId);
        return R.success(null, SUCCESSFULLY_DELETED);
    }

    @DeleteMapping("/messages")
    @ApiOperation("删除指定用户所有消息")
    public R<String> deleteUserMessage() {
        SecurityUtil.UserBO userBO = checkUserIsLogin();
        userService.deleteUserMessage(userBO.getUsername(), null);
        return R.success(null, SUCCESSFULLY_DELETED);
    }

    @PutMapping("/r/sub_credit")
    @ApiOperation("微服务远程调用扣减积分")
    public R<String> subCredit(
            @NotBlank(message = "用户姓名不能为空") @RequestParam("username") String username,
            @NotNull(message = "用户扣减积分不能为空") @RequestParam("credit") Integer credit
    ) {
        userService.subscriberUserCredit(username, credit);
        return R.success(null, UPDATE_SUCCESS);
    }

    @PutMapping("/r/rollback_credit")
    @ApiOperation("微服务远程调用任务撤销恢复积分")
    public R<String> rollbackCredit(
            @NotBlank(message = "用户姓名不能为空") @RequestParam("username") String username,
            @NotNull(message = "用户扣减积分不能为空") @RequestParam("credit") Integer credit
    ) {
        userService.rollbackCredit(username, credit);
        return R.success(null, UPDATE_SUCCESS);
    }

    @PutMapping("/r/star")
    @ApiOperation("微服务远程调用更新用户星级")
    public R<String> updateUserStar(
            @NotBlank(message = "用户姓名不能为空") @RequestParam("username") String username,
            @NotNull(message = "用户星级不能为空") @RequestParam("star") Integer star
    ) {
        userService.updateUserStarByUsername(username, star);
        return R.success(null, UPDATE_SUCCESS);
    }

    private SecurityUtil.UserBO checkUserIsLogin() {
        SecurityUtil.UserBO user = SecurityUtil.getUser();
        if (user == null) {
            log.info("当前用户未登录");
            throw new BizException(THE_USER_IS_NOT_LOGGED_IN_OR_THE_USER_DOES_NOT_EXIST.getCode(),
                    THE_USER_IS_NOT_LOGGED_IN_OR_THE_USER_DOES_NOT_EXIST.getMsg());
        }
        return user;
    }

}
